പൈത്തണിന്റെ അസിൻക്യോ ലോ-ലെവൽ നെറ്റ്വർക്കിംഗ് പഠിക്കാം. ട്രാൻസ്പോർട്ടുകളും പ്രോട്ടോക്കോളുകളും വിശദീകരിക്കുന്ന ഈ ഗൈഡ്, ഉയർന്ന പ്രകടനക്ഷമതയുള്ള നെറ്റ്വർക്ക് ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ സഹായിക്കും.
പൈത്തണിന്റെ അസിൻക്യോ ട്രാൻസ്പോർട്ടിനെ മനസ്സിലാക്കാം: ലോ-ലെവൽ നെറ്റ്വർക്കിംഗിലേക്കുള്ള ഒരു ആഴത്തിലുള്ള യാത്ര
ആധുനിക പൈത്തണിന്റെ ലോകത്ത്, ഉയർന്ന പ്രകടനക്ഷമതയുള്ള നെറ്റ്വർക്ക് പ്രോഗ്രാമിംഗിന്റെ ആണിക്കല്ലായി asyncio
മാറിയിരിക്കുന്നു. ഡെവലപ്പർമാർ പലപ്പോഴും ഇതിന്റെ മികച്ച ഹൈ-ലെവൽ API-കൾ ഉപയോഗിച്ചാണ് തുടങ്ങുന്നത്. aiohttp
അല്ലെങ്കിൽ FastAPI
പോലുള്ള ലൈബ്രറികളോടൊപ്പം async
, await
എന്നിവ ഉപയോഗിച്ച് വളരെ എളുപ്പത്തിൽ മികച്ച പ്രതികരണശേഷിയുള്ള ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ സാധിക്കുന്നു. asyncio.open_connection()
പോലുള്ള ഫംഗ്ഷനുകൾ നൽകുന്ന StreamReader
, StreamWriter
ഒബ്ജക്റ്റുകൾ, നെറ്റ്വർക്ക് I/O കൈകാര്യം ചെയ്യാൻ ലളിതവും ക്രമാനുഗതവുമായ ഒരു മാർഗ്ഗം നൽകുന്നു. എന്നാൽ ഈ അബ്സ്ട്രാക്ഷൻ മതിയാകാതെ വന്നാൽ എന്തുചെയ്യും? സങ്കീർണ്ണവും, സ്റ്റേറ്റ്ഫുൾ ആയതും, അല്ലെങ്കിൽ സാധാരണമല്ലാത്തതുമായ ഒരു നെറ്റ്വർക്ക് പ്രോട്ടോക്കോൾ നടപ്പിലാക്കണമെങ്കിൽ എന്തുചെയ്യും? അടിസ്ഥാനപരമായ കണക്ഷനെ നേരിട്ട് നിയന്ത്രിച്ച് പ്രകടനക്ഷമതയുടെ അവസാന തുള്ളിയും ഊറ്റിയെടുക്കണമെങ്കിൽ എന്തുചെയ്യും? ഇവിടെയാണ് അസിൻക്യോയുടെ നെറ്റ്വർക്കിംഗ് കഴിവുകളുടെ യഥാർത്ഥ അടിത്തറ നിലകൊള്ളുന്നത്: ലോ-ലെവൽ ട്രാൻസ്പോർട്ട്, പ്രോട്ടോക്കോൾ API. തുടക്കത്തിൽ ഇത് ഭയപ്പെടുത്തുന്നതായി തോന്നാമെങ്കിലും, ഈ ശക്തമായ ജോഡിയെ മനസ്സിലാക്കുന്നത് നിയന്ത്രണത്തിന്റെയും വഴക്കത്തിന്റെയും ഒരു പുതിയ തലം തുറന്നുതരുന്നു. ഇത് നിങ്ങൾക്ക് സങ്കൽപ്പിക്കാൻ കഴിയുന്ന ഏതൊരു നെറ്റ്വർക്ക് ആപ്ലിക്കേഷനും നിർമ്മിക്കാൻ പ്രാപ്തമാക്കുന്നു. ഈ സമഗ്രമായ ഗൈഡ് അബ്സ്ട്രാക്ഷന്റെ പാളികളെ വേർതിരിച്ച്, ട്രാൻസ്പോർട്ടുകളും പ്രോട്ടോക്കോളുകളും തമ്മിലുള്ള പരസ്പരാശ്രിത ബന്ധം പര്യവേക്ഷണം ചെയ്യുകയും, പൈത്തണിൽ ലോ-ലെവൽ അസിൻക്രണസ് നെറ്റ്വർക്കിംഗ് പഠിക്കാൻ നിങ്ങളെ സഹായിക്കുന്ന പ്രായോഗിക ഉദാഹരണങ്ങളിലൂടെ മുന്നോട്ട് കൊണ്ടുപോകുകയും ചെയ്യും.
അസിൻക്യോ നെറ്റ്വർക്കിംഗിന്റെ രണ്ട് മുഖങ്ങൾ: ഹൈ-ലെവൽ vs. ലോ-ലെവൽ
ലോ-ലെവൽ API-കളിലേക്ക് ആഴത്തിൽ കടക്കുന്നതിന് മുമ്പ്, അസിൻക്യോ ഇക്കോസിസ്റ്റത്തിനുള്ളിൽ അവയുടെ സ്ഥാനം മനസ്സിലാക്കേണ്ടത് അത്യാവശ്യമാണ്. അസിൻക്യോ നെറ്റ്വർക്ക് ആശയവിനിമയത്തിനായി രണ്ട് വ്യത്യസ്ത പാളികൾ നൽകുന്നു, ഓരോന്നും വ്യത്യസ്ത ഉപയോഗങ്ങൾക്കായി രൂപകൽപ്പന ചെയ്തിട്ടുള്ളവയാണ്.
ഹൈ-ലെവൽ API: സ്ട്രീമുകൾ
ഹൈ-ലെവൽ API, സാധാരണയായി "സ്ട്രീമുകൾ" എന്ന് അറിയപ്പെടുന്നു, ഇതാണ് മിക്ക ഡെവലപ്പർമാരും ആദ്യം പരിചയപ്പെടുന്നത്. നിങ്ങൾ asyncio.open_connection()
അല്ലെങ്കിൽ asyncio.start_server()
ഉപയോഗിക്കുമ്പോൾ, നിങ്ങൾക്ക് StreamReader
, StreamWriter
ഒബ്ജക്റ്റുകൾ ലഭിക്കുന്നു. ഈ API ലാളിത്യത്തിനും ഉപയോഗ എളുപ്പത്തിനും വേണ്ടി രൂപകൽപ്പന ചെയ്തിട്ടുള്ളതാണ്.
- ഇംപറേറ്റീവ് ശൈലി: ഇത് ക്രമാനുഗതമായി തോന്നുന്ന കോഡ് എഴുതാൻ നിങ്ങളെ അനുവദിക്കുന്നു. 100 ബൈറ്റുകൾ ലഭിക്കാൻ നിങ്ങൾ
await reader.read(100)
ഉപയോഗിക്കുന്നു, തുടർന്ന് ഒരു പ്രതികരണം അയയ്ക്കാൻwriter.write(data)
ഉപയോഗിക്കുന്നു. ഈasync/await
രീതി മനസ്സിലാക്കാൻ എളുപ്പമുള്ളതും യുക്തിസഹവുമാണ്. - സൗകര്യപ്രദമായ ഹെൽപ്പറുകൾ: ഇത്
readuntil(separator)
,readexactly(n)
പോലുള്ള രീതികൾ നൽകുന്നു, ഇത് സാധാരണ ഫ്രെയിമിംഗ് ജോലികൾ കൈകാര്യം ചെയ്യുകയും, ബഫറുകൾ സ്വയം കൈകാര്യം ചെയ്യുന്നതിൽ നിന്ന് നിങ്ങളെ രക്ഷിക്കുകയും ചെയ്യുന്നു. - അനുയോജ്യമായ ഉപയോഗങ്ങൾ: ലളിതമായ റിക്വസ്റ്റ്-റെസ്പോൺസ് പ്രോട്ടോക്കോളുകൾക്കും (ഒരു അടിസ്ഥാന HTTP ക്ലയിന്റ് പോലെ), ലൈൻ-ബേസ്ഡ് പ്രോട്ടോക്കോളുകൾക്കും (Redis അല്ലെങ്കിൽ SMTP പോലെ), അല്ലെങ്കിൽ ആശയവിനിമയം പ്രവചിക്കാവുന്ന, രേഖീയമായ ഒഴുക്ക് പിന്തുടരുന്ന ഏതൊരു സാഹചര്യത്തിനും ഇത് അനുയോജ്യമാണ്.
എന്നിരുന്നാലും, ഈ ലാളിത്യത്തിന് ഒരു പരിമിതിയുണ്ട്. എപ്പോൾ വേണമെങ്കിലും ആവശ്യപ്പെടാത്ത സന്ദേശങ്ങൾ വരാൻ സാധ്യതയുള്ള, ഉയർന്ന കൺകറന്റ്, ഇവന്റ്-ഡ്രിവൺ പ്രോട്ടോക്കോളുകൾക്ക് സ്ട്രീം-ബേസ്ഡ് സമീപനം അത്ര കാര്യക്ഷമമല്ലാത്തതാകാം. ഒരേസമയം റീഡുകളും റൈറ്റുകളും കൈകാര്യം ചെയ്യുന്നതിനോ സങ്കീർണ്ണമായ കണക്ഷൻ സ്റ്റേറ്റുകൾ കൈകാര്യം ചെയ്യുന്നതിനോ സീക്വൻഷ്യൽ await
മോഡൽ ബുദ്ധിമുട്ടാക്കിയേക്കാം.
ലോ-ലെവൽ API: ട്രാൻസ്പോർട്ടുകളും പ്രോട്ടോക്കോളുകളും
ഹൈ-ലെവൽ സ്ട്രീംസ് API യഥാർത്ഥത്തിൽ നിർമ്മിച്ചിരിക്കുന്നത് ഈ അടിസ്ഥാന പാളിയിലാണ്. ലോ-ലെവൽ API രണ്ട് വ്യത്യസ്ത ഘടകങ്ങളെ അടിസ്ഥാനമാക്കിയുള്ള ഒരു ഡിസൈൻ പാറ്റേൺ ഉപയോഗിക്കുന്നു: ട്രാൻസ്പോർട്ടുകളും പ്രോട്ടോക്കോളുകളും.
- ഇവന്റ്-ഡ്രിവൺ ശൈലി: ഡാറ്റ ലഭിക്കുന്നതിന് നിങ്ങൾ ഒരു ഫംഗ്ഷൻ വിളിക്കുന്നതിന് പകരം, സംഭവങ്ങൾ നടക്കുമ്പോൾ (ഉദാഹരണത്തിന്, ഒരു കണക്ഷൻ ഉണ്ടാകുമ്പോൾ, ഡാറ്റ ലഭിക്കുമ്പോൾ) അസിൻക്യോ നിങ്ങളുടെ ഒബ്ജക്റ്റിലെ മെത്തേഡുകളെ വിളിക്കുന്നു. ഇത് ഒരു കോൾബാക്ക്-ബേസ്ഡ് സമീപനമാണ്.
- ഉത്തരവാദിത്തങ്ങളുടെ വേർതിരിവ്: ഇത് "എന്ത് ചെയ്യണം" എന്നതിനെ "എങ്ങനെ ചെയ്യണം" എന്നതിൽ നിന്ന് വ്യക്തമായി വേർതിരിക്കുന്നു. പ്രോട്ടോക്കോൾ ഡാറ്റ ഉപയോഗിച്ച് എന്ത് ചെയ്യണമെന്ന് നിർവചിക്കുന്നു (നിങ്ങളുടെ ആപ്ലിക്കേഷൻ ലോജിക്), അതേസമയം ട്രാൻസ്പോർട്ട് ഡാറ്റ നെറ്റ്വർക്കിലൂടെ എങ്ങനെ അയയ്ക്കുകയും സ്വീകരിക്കുകയും ചെയ്യുന്നു എന്ന് കൈകാര്യം ചെയ്യുന്നു (I/O മെക്കാനിസം).
- പരമാവധി നിയന്ത്രണം: ഈ API ബഫറിംഗ്, ഫ്ലോ കൺട്രോൾ (ബാക്ക്പ്രഷർ), കണക്ഷൻ ലൈഫ് സൈക്കിൾ എന്നിവയിൽ നിങ്ങൾക്ക് സൂക്ഷ്മമായ നിയന്ത്രണം നൽകുന്നു.
- അനുയോജ്യമായ ഉപയോഗങ്ങൾ: കസ്റ്റം ബൈനറി അല്ലെങ്കിൽ ടെക്സ്റ്റ് പ്രോട്ടോക്കോളുകൾ നടപ്പിലാക്കുന്നതിനും, ആയിരക്കണക്കിന് പെർസിസ്റ്റന്റ് കണക്ഷനുകൾ കൈകാര്യം ചെയ്യുന്ന ഉയർന്ന പ്രകടനക്ഷമതയുള്ള സെർവറുകൾ നിർമ്മിക്കുന്നതിനും, അല്ലെങ്കിൽ നെറ്റ്വർക്ക് ഫ്രെയിംവർക്കുകളും ലൈബ്രറികളും വികസിപ്പിക്കുന്നതിനും ഇത് അത്യാവശ്യമാണ്.
ഇങ്ങനെ ചിന്തിക്കുക: സ്ട്രീംസ് API ഒരു മീൽ കിറ്റ് സർവീസ് ഓർഡർ ചെയ്യുന്നതുപോലെയാണ്. നിങ്ങൾക്ക് മുൻകൂട്ടി അളന്ന ചേരുവകളും പിന്തുടരാൻ ലളിതമായ ഒരു പാചകക്കുറിപ്പും ലഭിക്കുന്നു. ട്രാൻസ്പോർട്ട്, പ്രോട്ടോക്കോൾ API എന്നത് ഒരു പ്രൊഫഷണൽ അടുക്കളയിലെ ഷെഫിനെ പോലെയാണ്, അസംസ്കൃത വസ്തുക്കളും പ്രക്രിയയുടെ ഓരോ ഘട്ടത്തിലും പൂർണ്ണ നിയന്ത്രണവും ഉണ്ട്. രണ്ടും ഒരു മികച്ച ഭക്ഷണം ഉണ്ടാക്കാൻ സഹായിക്കും, എന്നാൽ രണ്ടാമത്തേത് അതിരുകളില്ലാത്ത സർഗ്ഗാത്മകതയും നിയന്ത്രണവും വാഗ്ദാനം ചെയ്യുന്നു.
പ്രധാന ഘടകങ്ങൾ: ട്രാൻസ്പോർട്ടുകളെയും പ്രോട്ടോക്കോളുകളെയും അടുത്തറിയാം
ലോ-ലെവൽ API-യുടെ ശക്തി വരുന്നത് പ്രോട്ടോക്കോളും ട്രാൻസ്പോർട്ടും തമ്മിലുള്ള മികച്ച ഇടപെടലിൽ നിന്നാണ്. ഏതൊരു ലോ-ലെവൽ അസിൻക്യോ നെറ്റ്വർക്ക് ആപ്ലിക്കേഷനിലും അവർ വ്യത്യസ്തരാണെങ്കിലും അഭേദ്യമായ പങ്കാളികളാണ്.
പ്രോട്ടോക്കോൾ: നിങ്ങളുടെ ആപ്ലിക്കേഷന്റെ തലച്ചോറ്
പ്രോട്ടോക്കോൾ എന്നത് നിങ്ങൾ എഴുതുന്ന ഒരു ക്ലാസാണ്. ഇത് asyncio.Protocol
-ൽ നിന്നോ (അല്ലെങ്കിൽ അതിന്റെ വകഭേദങ്ങളിലൊന്നിൽ നിന്നോ) ഇൻഹെറിറ്റ് ചെയ്യുന്നു, കൂടാതെ ഒരു നെറ്റ്വർക്ക് കണക്ഷൻ കൈകാര്യം ചെയ്യുന്നതിനുള്ള സ്റ്റേറ്റും ലോജിക്കും ഇതിൽ അടങ്ങിയിരിക്കുന്നു. നിങ്ങൾ ഈ ക്ലാസ് സ്വയം ഇൻസ്റ്റൻഷ്യേറ്റ് ചെയ്യേണ്ടതില്ല; നിങ്ങൾ അത് അസിൻക്യോയ്ക്ക് നൽകുന്നു (ഉദാഹരണത്തിന്, loop.create_server
-ലേക്ക്), ഓരോ പുതിയ ക്ലയിന്റ് കണക്ഷനും വേണ്ടി അസിൻക്യോ നിങ്ങളുടെ പ്രോട്ടോക്കോളിന്റെ ഒരു പുതിയ ഇൻസ്റ്റൻസ് ഉണ്ടാക്കുന്നു.
കണക്ഷന്റെ ലൈഫ് സൈക്കിളിലെ വിവിധ ഘട്ടങ്ങളിൽ ഇവന്റ് ലൂപ്പ് വിളിക്കുന്ന ഒരു കൂട്ടം ഇവന്റ് ഹാൻഡ്ലർ മെത്തേഡുകളാൽ നിങ്ങളുടെ പ്രോട്ടോക്കോൾ ക്ലാസ് നിർവചിക്കപ്പെടുന്നു. ഏറ്റവും പ്രധാനപ്പെട്ടവ ഇവയാണ്:
connection_made(self, transport)
ഒരു പുതിയ കണക്ഷൻ വിജയകരമായി സ്ഥാപിക്കുമ്പോൾ കൃത്യമായി ഒരു തവണ വിളിക്കപ്പെടുന്നു. ഇതാണ് നിങ്ങളുടെ എൻട്രി പോയിന്റ്. ഇവിടെയാണ് നിങ്ങൾക്ക് transport
ഒബ്ജക്റ്റ് ലഭിക്കുന്നത്, അത് കണക്ഷനെ പ്രതിനിധീകരിക്കുന്നു. നിങ്ങൾ എല്ലായ്പ്പോഴും അതിന്റെ ഒരു റഫറൻസ് സൂക്ഷിക്കണം, സാധാരണയായി self.transport
ആയി. ബഫറുകൾ സജ്ജീകരിക്കുന്നത് അല്ലെങ്കിൽ പിയറിന്റെ വിലാസം ലോഗ് ചെയ്യുന്നത് പോലുള്ള ഓരോ കണക്ഷനും വേണ്ടിയുള്ള ഏതൊരു ഇനീഷ്യലൈസേഷനും നടത്താൻ ഇത് അനുയോജ്യമായ സ്ഥലമാണ്.
data_received(self, data)
നിങ്ങളുടെ പ്രോട്ടോക്കോളിന്റെ ഹൃദയം. കണക്ഷന്റെ മറ്റേ അറ്റത്ത് നിന്ന് പുതിയ ഡാറ്റ ലഭിക്കുമ്പോഴെല്ലാം ഈ മെത്തേഡ് വിളിക്കപ്പെടുന്നു. data
ആർഗ്യുമെന്റ് ഒരു bytes
ഒബ്ജക്റ്റാണ്. TCP ഒരു സന്ദേശ പ്രോട്ടോക്കോളല്ല, ഒരു സ്ട്രീം പ്രോട്ടോക്കോളാണ് എന്ന് ഓർമ്മിക്കേണ്ടത് അത്യാവശ്യമാണ്. നിങ്ങളുടെ ആപ്ലിക്കേഷനിൽ നിന്നുള്ള ഒരു ലോജിക്കൽ സന്ദേശം ഒന്നിലധികം data_received
കോളുകളിലായി വിഭജിക്കപ്പെടാം, അല്ലെങ്കിൽ ഒന്നിലധികം ചെറിയ സന്ദേശങ്ങൾ ഒരു കോളിൽ ഒന്നിച്ചുകൂടാം. നിങ്ങളുടെ കോഡ് ഈ ബഫറിംഗും പാർസിംഗും കൈകാര്യം ചെയ്യണം.
connection_lost(self, exc)
കണക്ഷൻ അടയ്ക്കുമ്പോൾ വിളിക്കപ്പെടുന്നു. ഇത് പല കാരണങ്ങളാൽ സംഭവിക്കാം. കണക്ഷൻ വൃത്തിയായി അടച്ചാൽ (ഉദാഹരണത്തിന്, മറ്റേ ഭാഗം അത് അടയ്ക്കുന്നു, അല്ലെങ്കിൽ നിങ്ങൾ transport.close()
വിളിക്കുന്നു), exc
എന്നത് None
ആയിരിക്കും. ഒരു പിശക് കാരണം കണക്ഷൻ അടച്ചാൽ (ഉദാഹരണത്തിന്, നെറ്റ്വർക്ക് തകരാർ, റീസെറ്റ്), exc
പിശക് വിശദമാക്കുന്ന ഒരു എക്സെപ്ഷൻ ഒബ്ജക്റ്റ് ആയിരിക്കും. ക്ലീനപ്പ് നടത്താനും, ഡിസ്കണക്ഷൻ ലോഗ് ചെയ്യാനും, അല്ലെങ്കിൽ നിങ്ങൾ ഒരു ക്ലയിന്റ് നിർമ്മിക്കുകയാണെങ്കിൽ വീണ്ടും കണക്റ്റുചെയ്യാൻ ശ്രമിക്കാനും ഇത് നിങ്ങളുടെ അവസരമാണ്.
eof_received(self)
ഇതൊരു സൂക്ഷ്മമായ കോൾബാക്ക് ആണ്. മറ്റേ അറ്റം ഇനി ഡാറ്റ അയയ്ക്കില്ലെന്ന് സൂചിപ്പിക്കുമ്പോൾ (ഉദാഹരണത്തിന്, ഒരു POSIX സിസ്റ്റത്തിൽ shutdown(SHUT_WR)
വിളിക്കുന്നതിലൂടെ) ഇത് വിളിക്കപ്പെടുന്നു, പക്ഷേ നിങ്ങൾക്ക് ഡാറ്റ അയയ്ക്കുന്നതിനായി കണക്ഷൻ ഇപ്പോഴും തുറന്നിരിക്കാം. നിങ്ങൾ ഈ മെത്തേഡിൽ നിന്ന് True
റിട്ടേൺ ചെയ്താൽ, ട്രാൻസ്പോർട്ട് അടയ്ക്കപ്പെടും. നിങ്ങൾ False
(ഡിഫോൾട്ട്) റിട്ടേൺ ചെയ്താൽ, പിന്നീട് ട്രാൻസ്പോർട്ട് സ്വയം അടയ്ക്കുന്നതിനുള്ള ഉത്തരവാദിത്തം നിങ്ങൾക്കാണ്.
ട്രാൻസ്പോർട്ട്: ആശയവിനിമയ ചാനൽ
ട്രാൻസ്പോർട്ട് എന്നത് അസിൻക്യോ നൽകുന്ന ഒരു ഒബ്ജക്റ്റാണ്. നിങ്ങൾ അത് ഉണ്ടാക്കുന്നില്ല; നിങ്ങളുടെ പ്രോട്ടോക്കോളിന്റെ connection_made
മെത്തേഡിൽ നിങ്ങൾക്ക് അത് ലഭിക്കുന്നു. ഇത് അടിസ്ഥാന നെറ്റ്വർക്ക് സോക്കറ്റിനും ഇവന്റ് ലൂപ്പിന്റെ I/O ഷെഡ്യൂളിംഗിനും മുകളിലുള്ള ഒരു ഹൈ-ലെവൽ അബ്സ്ട്രാക്ഷനായി പ്രവർത്തിക്കുന്നു. ഡാറ്റ അയയ്ക്കുന്നതും കണക്ഷന്റെ നിയന്ത്രണവും കൈകാര്യം ചെയ്യുക എന്നതാണ് ഇതിന്റെ പ്രധാന ജോലി.
അതിന്റെ മെത്തേഡുകളിലൂടെ നിങ്ങൾ ട്രാൻസ്പോർട്ടുമായി സംവദിക്കുന്നു:
transport.write(data)
ഡാറ്റ അയയ്ക്കുന്നതിനുള്ള പ്രധാന മെത്തേഡ്. data
ഒരു bytes
ഒബ്ജക്റ്റ് ആയിരിക്കണം. ഈ മെത്തേഡ് നോൺ-ബ്ലോക്കിംഗ് ആണ്. ഇത് ഡാറ്റ ഉടനടി അയയ്ക്കുന്നില്ല. പകരം, ഇത് ഡാറ്റയെ ഒരു ഇന്റേണൽ റൈറ്റ് ബഫറിലേക്ക് മാറ്റുന്നു, ഇവന്റ് ലൂപ്പ് കഴിയുന്നത്ര കാര്യക്ഷമമായി പശ്ചാത്തലത്തിൽ നെറ്റ്വർക്കിലൂടെ അത് അയയ്ക്കുന്നു.
transport.writelines(list_of_data)
ഒന്നിലധികം bytes
ഒബ്ജക്റ്റുകളുടെ ഒരു സീക്വൻസ് ഒരേസമയം ബഫറിലേക്ക് എഴുതാനുള്ള കൂടുതൽ കാര്യക്ഷമമായ മാർഗ്ഗം, ഇത് സിസ്റ്റം കോളുകളുടെ എണ്ണം കുറയ്ക്കാൻ സഹായിച്ചേക്കാം.
transport.close()
ഇതൊരു ഗ്രേസ്ഫുൾ ഷട്ട്ഡൗൺ ആരംഭിക്കുന്നു. ട്രാൻസ്പോർട്ട് ആദ്യം അതിന്റെ റൈറ്റ് ബഫറിൽ ശേഷിക്കുന്ന ഏതെങ്കിലും ഡാറ്റ ഫ്ലഷ് ചെയ്യുകയും തുടർന്ന് കണക്ഷൻ അടയ്ക്കുകയും ചെയ്യും. close()
വിളിച്ചതിനു ശേഷം കൂടുതൽ ഡാറ്റ എഴുതാൻ കഴിയില്ല.
transport.abort()
ഇതൊരു ഹാർഡ് ഷട്ട്ഡൗൺ നടത്തുന്നു. കണക്ഷൻ ഉടനടി അടയ്ക്കപ്പെടുന്നു, റൈറ്റ് ബഫറിൽ ശേഷിക്കുന്ന ഏതെങ്കിലും ഡാറ്റ ഉപേക്ഷിക്കപ്പെടുന്നു. അസാധാരണ സാഹചര്യങ്ങളിൽ ഇത് ഉപയോഗിക്കണം.
transport.get_extra_info(name, default=None)
ആത്മപരിശോധനയ്ക്ക് വളരെ ഉപയോഗപ്രദമായ ഒരു മെത്തേഡ്. പിയറിന്റെ വിലാസം ('peername'
), അടിസ്ഥാന സോക്കറ്റ് ഒബ്ജക്റ്റ് ('socket'
), അല്ലെങ്കിൽ SSL/TLS സർട്ടിഫിക്കറ്റ് വിവരങ്ങൾ ('ssl_object'
) പോലുള്ള കണക്ഷനെക്കുറിച്ചുള്ള വിവരങ്ങൾ നിങ്ങൾക്ക് ലഭിക്കും.
പരസ്പരാശ്രിത ബന്ധം
ഈ രൂപകൽപ്പനയുടെ ഭംഗി വിവരങ്ങളുടെ വ്യക്തവും ചാക്രികവുമായ ഒഴുക്കാണ്:
- സജ്ജീകരണം: ഇവന്റ് ലൂപ്പ് ഒരു പുതിയ കണക്ഷൻ സ്വീകരിക്കുന്നു.
- ഇൻസ്റ്റൻഷ്യേഷൻ: ലൂപ്പ് നിങ്ങളുടെ
Protocol
ക്ലാസിന്റെ ഒരു ഇൻസ്റ്റൻസും കണക്ഷനെ പ്രതിനിധീകരിക്കുന്ന ഒരുTransport
ഒബ്ജക്റ്റും ഉണ്ടാക്കുന്നു. - ബന്ധിപ്പിക്കൽ: ലൂപ്പ്
your_protocol.connection_made(transport)
വിളിക്കുന്നു, രണ്ട് ഒബ്ജക്റ്റുകളെയും ഒരുമിച്ച് ബന്ധിപ്പിക്കുന്നു. നിങ്ങളുടെ പ്രോട്ടോക്കോളിന് ഇപ്പോൾ ഡാറ്റ അയയ്ക്കാനുള്ള ഒരു മാർഗ്ഗമുണ്ട്. - ഡാറ്റ സ്വീകരിക്കുന്നു: നെറ്റ്വർക്ക് സോക്കറ്റിൽ ഡാറ്റ വരുമ്പോൾ, ഇവന്റ് ലൂപ്പ് ഉണരുകയും, ഡാറ്റ വായിക്കുകയും,
your_protocol.data_received(data)
വിളിക്കുകയും ചെയ്യുന്നു. - പ്രോസസ്സിംഗ്: നിങ്ങളുടെ പ്രോട്ടോക്കോളിന്റെ ലോജിക് ലഭിച്ച ഡാറ്റ പ്രോസസ്സ് ചെയ്യുന്നു.
- ഡാറ്റ അയയ്ക്കുന്നു: അതിന്റെ ലോജിക്കിനെ അടിസ്ഥാനമാക്കി, നിങ്ങളുടെ പ്രോട്ടോക്കോൾ ഒരു മറുപടി അയയ്ക്കാൻ
self.transport.write(response_data)
വിളിക്കുന്നു. ഡാറ്റ ബഫർ ചെയ്യപ്പെടുന്നു. - പശ്ചാത്തല I/O: ഇവന്റ് ലൂപ്പ് ട്രാൻസ്പോർട്ടിലൂടെ ബഫർ ചെയ്ത ഡാറ്റയുടെ നോൺ-ബ്ലോക്കിംഗ് അയയ്ക്കൽ കൈകാര്യം ചെയ്യുന്നു.
- അവസാനിപ്പിക്കൽ: കണക്ഷൻ അവസാനിക്കുമ്പോൾ, ഇവന്റ് ലൂപ്പ് അന്തിമ ക്ലീനപ്പിനായി
your_protocol.connection_lost(exc)
വിളിക്കുന്നു.
ഒരു പ്രായോഗിക ഉദാഹരണം നിർമ്മിക്കാം: ഒരു എക്കോ സെർവറും ക്ലയിന്റും
സിദ്ധാന്തം നല്ലതാണ്, എന്നാൽ ട്രാൻസ്പോർട്ടുകളും പ്രോട്ടോക്കോളുകളും മനസ്സിലാക്കാനുള്ള ഏറ്റവും നല്ല മാർഗ്ഗം എന്തെങ്കിലും നിർമ്മിക്കുക എന്നതാണ്. നമുക്ക് ഒരു ക്ലാസിക് എക്കോ സെർവറും അതിനനുസരിച്ചുള്ള ഒരു ക്ലയിന്റും ഉണ്ടാക്കാം. സെർവർ കണക്ഷനുകൾ സ്വീകരിക്കുകയും ലഭിക്കുന്ന ഏതൊരു ഡാറ്റയും തിരികെ അയയ്ക്കുകയും ചെയ്യും.
എക്കോ സെർവർ നിർമ്മാണം
ആദ്യം, നമ്മൾ നമ്മുടെ സെർവർ-സൈഡ് പ്രോട്ടോക്കോൾ നിർവചിക്കും. ഇത് വളരെ ലളിതമാണ്, പ്രധാന ഇവന്റ് ഹാൻഡ്ലറുകൾ കാണിക്കുന്നു.
import asyncio
class EchoServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
# ഒരു പുതിയ കണക്ഷൻ സ്ഥാപിക്കപ്പെട്ടു.
# ലോഗിങ്ങിനായി റിമോട്ട് അഡ്രസ്സ് എടുക്കുക.
peername = transport.get_extra_info('peername')
print(f"Connection from: {peername}")
# പിന്നീട് ഉപയോഗിക്കുന്നതിനായി ട്രാൻസ്പോർട്ട് സംഭരിക്കുക.
self.transport = transport
def data_received(self, data):
# ക്ലയിന്റിൽ നിന്ന് ഡാറ്റ ലഭിച്ചു.
message = data.decode()
print(f"Data received: {message.strip()}")
# ഡാറ്റ ക്ലയിന്റിലേക്ക് തിരികെ എക്കോ ചെയ്യുക.
print(f"Echoing back: {message.strip()}")
self.transport.write(data)
def connection_lost(self, exc):
# കണക്ഷൻ അടച്ചു.
print("Connection closed.")
# ട്രാൻസ്പോർട്ട് സ്വയമേവ അടയ്ക്കപ്പെടുന്നു, ഇവിടെ self.transport.close() വിളിക്കേണ്ട ആവശ്യമില്ല.
async def main_server():
# സെർവർ അനിശ്ചിതമായി പ്രവർത്തിപ്പിക്കാൻ ഉദ്ദേശിക്കുന്നതിനാൽ ഇവന്റ് ലൂപ്പിലേക്ക് ഒരു റഫറൻസ് നേടുക.
loop = asyncio.get_running_loop()
host = '127.0.0.1'
port = 8888
# `create_server` കോറൂട്ടീൻ സെർവർ ഉണ്ടാക്കുകയും ആരംഭിക്കുകയും ചെയ്യുന്നു.
# ആദ്യത്തെ ആർഗ്യുമെന്റ് protocol_factory ആണ്, ഇത് ഒരു പുതിയ പ്രോട്ടോക്കോൾ ഇൻസ്റ്റൻസ് നൽകുന്ന ഒരു കോളബിൾ ആണ്.
# നമ്മുടെ കാര്യത്തിൽ, `EchoServerProtocol` എന്ന ക്ലാസ് പാസ്സ് ചെയ്താൽ മതി.
server = await loop.create_server(
lambda: EchoServerProtocol(),
host,
port)
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
print(f'Serving on {addrs}')
# സെർവർ പശ്ചാത്തലത്തിൽ പ്രവർത്തിക്കുന്നു. പ്രധാന കോറൂട്ടീൻ സജീവമായി നിലനിർത്താൻ,
# നമുക്ക് ഒരിക്കലും പൂർത്തിയാകാത്ത ഒന്നിനായി കാത്തിരിക്കാം, ഒരു പുതിയ ഫ്യൂച്ചർ പോലെ.
# ഈ ഉദാഹരണത്തിനായി, നമ്മൾ ഇത് "എന്നേക്കും" പ്രവർത്തിപ്പിക്കും.
async with server:
await server.serve_forever()
if __name__ == "__main__":
try:
# സെർവർ പ്രവർത്തിപ്പിക്കാൻ:
asyncio.run(main_server())
except KeyboardInterrupt:
print("Server shut down.")
ഈ സെർവർ കോഡിൽ, loop.create_server()
ആണ് പ്രധാനം. ഇത് നിർദ്ദിഷ്ട ഹോസ്റ്റിലേക്കും പോർട്ടിലേക്കും ബൈൻഡ് ചെയ്യുകയും പുതിയ കണക്ഷനുകൾക്കായി കാത്തിരിക്കാൻ ഇവന്റ് ലൂപ്പിനോട് പറയുകയും ചെയ്യുന്നു. ഓരോ ഇൻകമിംഗ് കണക്ഷനും, ആ പ്രത്യേക ക്ലയിന്റിനായി ഒരു പുതിയ പ്രോട്ടോക്കോൾ ഇൻസ്റ്റൻസ് ഉണ്ടാക്കാൻ ഇത് നമ്മുടെ protocol_factory
(lambda: EchoServerProtocol()
ഫംഗ്ഷൻ) വിളിക്കുന്നു.
എക്കോ ക്ലയിന്റ് നിർമ്മാണം
ക്ലയിന്റ് പ്രോട്ടോക്കോൾ അല്പം കൂടുതൽ സങ്കീർണ്ണമാണ്, കാരണം അതിന് സ്വന്തം സ്റ്റേറ്റ് കൈകാര്യം ചെയ്യേണ്ടതുണ്ട്: എന്ത് സന്ദേശം അയയ്ക്കണം, എപ്പോഴാണ് അതിന്റെ ജോലി "പൂർത്തിയായി" എന്ന് കണക്കാക്കുന്നത്. ക്ലയിന്റ് ആരംഭിച്ച പ്രധാന കോറൂട്ടീനിലേക്ക് പൂർത്തീകരണം സൂചിപ്പിക്കാൻ ഒരു asyncio.Future
അല്ലെങ്കിൽ asyncio.Event
ഉപയോഗിക്കുന്നത് ഒരു സാധാരണ രീതിയാണ്.
import asyncio
class EchoClientProtocol(asyncio.Protocol):
def __init__(self, message, on_con_lost):
self.message = message
self.on_con_lost = on_con_lost
self.transport = None
def connection_made(self, transport):
self.transport = transport
print(f"Sending: {self.message}")
self.transport.write(self.message.encode())
def data_received(self, data):
print(f"Received echo: {data.decode().strip()}")
def connection_lost(self, exc):
print("The server closed the connection")
# കണക്ഷൻ നഷ്ടപ്പെട്ടുവെന്നും ടാസ്ക് പൂർത്തിയായെന്നും സൂചിപ്പിക്കുക.
self.on_con_lost.set_result(True)
def eof_received(self):
# സെർവർ അടയ്ക്കുന്നതിന് മുമ്പ് ഒരു EOF അയച്ചാൽ ഇത് വിളിക്കപ്പെടാം.
print("Received EOF from server.")
async def main_client():
loop = asyncio.get_running_loop()
# ക്ലയിന്റിന്റെ ജോലി പൂർത്തിയായെന്ന് സൂചിപ്പിക്കാൻ on_con_lost ഫ്യൂച്ചർ ഉപയോഗിക്കുന്നു.
on_con_lost = loop.create_future()
message = "Hello World!"
host = '127.0.0.1'
port = 8888
# `create_connection` കണക്ഷൻ സ്ഥാപിക്കുകയും പ്രോട്ടോക്കോളിനെ ബന്ധിപ്പിക്കുകയും ചെയ്യുന്നു.
try:
transport, protocol = await loop.create_connection(
lambda: EchoClientProtocol(message, on_con_lost),
host,
port)
except ConnectionRefusedError:
print("Connection refused. Is the server running?")
return
# പ്രോട്ടോക്കോൾ കണക്ഷൻ നഷ്ടപ്പെട്ടുവെന്ന് സൂചിപ്പിക്കുന്നത് വരെ കാത്തിരിക്കുക.
try:
await on_con_lost
finally:
# ട്രാൻസ്പോർട്ട് ഭംഗിയായി അടയ്ക്കുക.
transport.close()
if __name__ == "__main__":
# ക്ലയിന്റ് പ്രവർത്തിപ്പിക്കാൻ:
# ആദ്യം, ഒരു ടെർമിനലിൽ സെർവർ ആരംഭിക്കുക.
# തുടർന്ന്, ഈ സ്ക്രിപ്റ്റ് മറ്റൊരു ടെർമിനലിൽ പ്രവർത്തിപ്പിക്കുക.
asyncio.run(main_client())
ഇവിടെ, loop.create_connection()
എന്നത് create_server
-ന്റെ ക്ലയിന്റ്-സൈഡ് പതിപ്പാണ്. ഇത് നൽകിയിട്ടുള്ള വിലാസത്തിലേക്ക് കണക്റ്റുചെയ്യാൻ ശ്രമിക്കുന്നു. വിജയകരമായാൽ, അത് നമ്മുടെ EchoClientProtocol
-നെ ഇൻസ്റ്റൻഷ്യേറ്റ് ചെയ്യുകയും അതിന്റെ connection_made
മെത്തേഡ് വിളിക്കുകയും ചെയ്യുന്നു. on_con_lost
ഫ്യൂച്ചറിന്റെ ഉപയോഗം ഒരു നിർണായക പാറ്റേൺ ആണ്. main_client
കോറൂട്ടീൻ ഈ ഫ്യൂച്ചറിനായി await
ചെയ്യുന്നു, connection_lost
-നുള്ളിൽ നിന്ന് on_con_lost.set_result(True)
വിളിച്ച് പ്രോട്ടോക്കോൾ അതിന്റെ ജോലി പൂർത്തിയായി എന്ന് സൂചിപ്പിക്കുന്നത് വരെ സ്വന്തം എക്സിക്യൂഷൻ താൽക്കാലികമായി നിർത്തുന്നു.
വിപുലമായ ആശയങ്ങളും യഥാർത്ഥ ലോക സാഹചര്യങ്ങളും
എക്കോ ഉദാഹരണം അടിസ്ഥാനകാര്യങ്ങൾ ഉൾക്കൊള്ളുന്നു, എന്നാൽ യഥാർത്ഥ ലോക പ്രോട്ടോക്കോളുകൾ അപൂർവ്വമായി അത്ര ലളിതമാണ്. നിങ്ങൾ തീർച്ചയായും നേരിടാൻ പോകുന്ന ചില വിപുലമായ വിഷയങ്ങൾ നമുക്ക് പര്യവേക്ഷണം ചെയ്യാം.
സന്ദേശ ഫ്രെയിമിംഗും ബഫറിംഗും കൈകാര്യം ചെയ്യൽ
അടിസ്ഥാനകാര്യങ്ങൾക്ക് ശേഷം മനസ്സിലാക്കേണ്ട ഏറ്റവും പ്രധാനപ്പെട്ട ആശയം TCP ഒരു ബൈറ്റുകളുടെ സ്ട്രീം ആണ് എന്നതാണ്. അതിന് അന്തർലീനമായ "സന്ദേശ" അതിരുകളില്ല. ഒരു ക്ലയിന്റ് "Hello" എന്നും തുടർന്ന് "World" എന്നും അയച്ചാൽ, നിങ്ങളുടെ സെർവറിന്റെ data_received
ഒരു തവണ b'HelloWorld'
ഉപയോഗിച്ച് വിളിക്കാം, അല്ലെങ്കിൽ രണ്ട് തവണ b'Hello'
, b'World'
എന്നിവ ഉപയോഗിച്ച് വിളിക്കാം, അല്ലെങ്കിൽ ഭാഗികമായ ഡാറ്റ ഉപയോഗിച്ച് പലതവണ പോലും വിളിക്കാം.
ഈ ബൈറ്റ് സ്ട്രീമുകളെ അർത്ഥവത്തായ സന്ദേശങ്ങളായി പുനഃക്രമീകരിക്കുന്ന "ഫ്രെയിമിംഗ്" നിങ്ങളുടെ പ്രോട്ടോക്കോളിന്റെ ഉത്തരവാദിത്തമാണ്. ഒരു ന്യൂലൈൻ കാരക്ടർ (\n
) പോലുള്ള ഒരു ഡിലിമിറ്റർ ഉപയോഗിക്കുന്നത് ഒരു സാധാരണ തന്ത്രമാണ്.
ഒരു ന്യൂലൈൻ കണ്ടെത്തുന്നതുവരെ ഡാറ്റ ബഫർ ചെയ്യുകയും, ഒരു സമയം ഒരു ലൈൻ പ്രോസസ്സ് ചെയ്യുകയും ചെയ്യുന്ന ഒരു പരിഷ്കരിച്ച പ്രോട്ടോക്കോൾ താഴെ നൽകുന്നു.
class LineBasedProtocol(asyncio.Protocol):
def __init__(self):
self._buffer = b''
self.transport = None
def connection_made(self, transport):
self.transport = transport
print("Connection established.")
def data_received(self, data):
# പുതിയ ഡാറ്റ ഇന്റേണൽ ബഫറിലേക്ക് ചേർക്കുക
self._buffer += data
# ബഫറിലുള്ള പൂർണ്ണമായ ലൈനുകൾ പ്രോസസ്സ് ചെയ്യുക
while b'\n' in self._buffer:
line, self._buffer = self._buffer.split(b'\n', 1)
self.process_line(line.decode().strip())
def process_line(self, line):
# ഇവിടെയാണ് ഒരൊറ്റ സന്ദേശത്തിനുള്ള നിങ്ങളുടെ ആപ്ലിക്കേഷൻ ലോജിക് വരുന്നത്
print(f"Processing complete message: {line}")
response = f"Processed: {line}\n"
self.transport.write(response.encode())
def connection_lost(self, exc):
print("Connection lost.")
ഫ്ലോ കൺട്രോൾ (ബാക്ക്പ്രഷർ) കൈകാര്യം ചെയ്യൽ
നിങ്ങളുടെ ആപ്ലിക്കേഷൻ നെറ്റ്വർക്കിനോ റിമോട്ട് പിയറിനോ കൈകാര്യം ചെയ്യാൻ കഴിയുന്നതിലും വേഗത്തിൽ ട്രാൻസ്പോർട്ടിലേക്ക് ഡാറ്റ എഴുതുകയാണെങ്കിൽ എന്ത് സംഭവിക്കും? ഡാറ്റ ട്രാൻസ്പോർട്ടിന്റെ ഇന്റേണൽ ബഫറിൽ കുന്നുകൂടുന്നു. ഇത് നിയന്ത്രണമില്ലാതെ തുടരുകയാണെങ്കിൽ, ബഫർ അനന്തമായി വളരുകയും ലഭ്യമായ മെമ്മറി മുഴുവൻ ഉപയോഗിക്കുകയും ചെയ്യും. ഈ പ്രശ്നം "ബാക്ക്പ്രഷർ" ഇല്ലായ്മ എന്നറിയപ്പെടുന്നു.
ഇത് കൈകാര്യം ചെയ്യാൻ അസിൻക്യോ ഒരു സംവിധാനം നൽകുന്നു. ട്രാൻസ്പോർട്ട് സ്വന്തം ബഫർ വലുപ്പം നിരീക്ഷിക്കുന്നു. ബഫർ ഒരു നിശ്ചിത ഹൈ-വാട്ടർ മാർക്കിന് മുകളിൽ വളരുമ്പോൾ, ഇവന്റ് ലൂപ്പ് നിങ്ങളുടെ പ്രോട്ടോക്കോളിന്റെ pause_writing()
മെത്തേഡ് വിളിക്കുന്നു. ഇത് നിങ്ങളുടെ ആപ്ലിക്കേഷന് ഡാറ്റ അയയ്ക്കുന്നത് നിർത്താനുള്ള ഒരു സൂചനയാണ്. ബഫർ ഒരു ലോ-വാട്ടർ മാർക്കിന് താഴെയായി ശൂന്യമാകുമ്പോൾ, ലൂപ്പ് resume_writing()
വിളിക്കുന്നു, ഇത് ഡാറ്റ വീണ്ടും അയയ്ക്കാൻ സുരക്ഷിതമാണെന്ന് സൂചിപ്പിക്കുന്നു.
class FlowControlledProtocol(asyncio.Protocol):
def __init__(self):
self._paused = False
self._data_source = some_data_generator() # ഒരു ഡാറ്റാ ഉറവിടം സങ്കൽപ്പിക്കുക
self.transport = None
def connection_made(self, transport):
self.transport = transport
self.resume_writing() # എഴുതുന്ന പ്രക്രിയ ആരംഭിക്കുക
def pause_writing(self):
# ട്രാൻസ്പോർട്ട് ബഫർ നിറഞ്ഞിരിക്കുന്നു.
print("Pausing writing.")
self._paused = True
def resume_writing(self):
# ട്രാൻസ്പോർട്ട് ബഫർ ശൂന്യമായി.
print("Resuming writing.")
self._paused = False
self._write_more_data()
def _write_more_data(self):
# ഇത് നമ്മുടെ ആപ്ലിക്കേഷന്റെ റൈറ്റ് ലൂപ്പാണ്.
while not self._paused:
try:
data = next(self._data_source)
self.transport.write(data)
except StopIteration:
self.transport.close()
break # അയയ്ക്കാൻ കൂടുതൽ ഡാറ്റയില്ല
# ഉടനടി നിർത്തണമോ എന്ന് കാണാൻ ബഫർ വലുപ്പം പരിശോധിക്കുക
if self.transport.get_write_buffer_size() > 0:
self.pause_writing()
TCP-ക്ക് അപ്പുറം: മറ്റ് ട്രാൻസ്പോർട്ടുകൾ
TCP ഏറ്റവും സാധാരണമായ ഉപയോഗമാണെങ്കിലും, ട്രാൻസ്പോർട്ട്/പ്രോട്ടോക്കോൾ പാറ്റേൺ അതിൽ മാത്രം ഒതുങ്ങുന്നില്ല. അസിൻക്യോ മറ്റ് ആശയവിനിമയ തരങ്ങൾക്കായി അബ്സ്ട്രാക്ഷനുകൾ നൽകുന്നു:
- UDP: കണക്ഷൻലെസ് ആശയവിനിമയത്തിനായി, നിങ്ങൾ
loop.create_datagram_endpoint()
ഉപയോഗിക്കുന്നു. ഇത് നിങ്ങൾക്ക് ഒരുDatagramTransport
നൽകുന്നു, കൂടാതെ നിങ്ങൾdatagram_received(data, addr)
,error_received(exc)
പോലുള്ള മെത്തേഡുകളുള്ള ഒരുasyncio.DatagramProtocol
നടപ്പിലാക്കും. - SSL/TLS: എൻക്രിപ്ഷൻ ചേർക്കുന്നത് വളരെ എളുപ്പമാണ്. നിങ്ങൾ
loop.create_server()
അല്ലെങ്കിൽloop.create_connection()
എന്നതിലേക്ക് ഒരുssl.SSLContext
ഒബ്ജക്റ്റ് പാസ്സ് ചെയ്യുന്നു. അസിൻക്യോ TLS ഹാൻഡ്ഷേക്ക് സ്വയമേവ കൈകാര്യം ചെയ്യുന്നു, നിങ്ങൾക്ക് ഒരു സുരക്ഷിത ട്രാൻസ്പോർട്ട് ലഭിക്കുന്നു. നിങ്ങളുടെ പ്രോട്ടോക്കോൾ കോഡിൽ ഒരു മാറ്റവും വരുത്തേണ്ടതില്ല. - സബ്പ്രോസസ്സുകൾ: ചൈൽഡ് പ്രോസസ്സുകളുമായി അവയുടെ സ്റ്റാൻഡേർഡ് I/O പൈപ്പുകൾ വഴി ആശയവിനിമയം നടത്താൻ,
loop.subprocess_exec()
,loop.subprocess_shell()
എന്നിവ ഒരുasyncio.SubprocessProtocol
ഉപയോഗിച്ച് ഉപയോഗിക്കാം. ഇത് പൂർണ്ണമായും അസിൻക്രണസ്, നോൺ-ബ്ലോക്കിംഗ് രീതിയിൽ ചൈൽഡ് പ്രോസസ്സുകൾ കൈകാര്യം ചെയ്യാൻ നിങ്ങളെ അനുവദിക്കുന്നു.
തന്ത്രപരമായ തീരുമാനം: എപ്പോൾ ട്രാൻസ്പോർട്ടുകൾ ഉപയോഗിക്കണം vs. സ്ട്രീമുകൾ
നിങ്ങളുടെ പക്കൽ രണ്ട് ശക്തമായ API-കൾ ഉള്ളപ്പോൾ, ജോലിക്കായി ശരിയായത് തിരഞ്ഞെടുക്കുന്നത് ഒരു പ്രധാന ആർക്കിടെക്ചറൽ തീരുമാനമാണ്. തീരുമാനിക്കാൻ നിങ്ങളെ സഹായിക്കുന്ന ഒരു ഗൈഡ് ഇതാ.
സ്ട്രീമുകൾ (StreamReader
/StreamWriter
) തിരഞ്ഞെടുക്കേണ്ട സാഹചര്യങ്ങൾ...
- നിങ്ങളുടെ പ്രോട്ടോക്കോൾ ലളിതവും റിക്വസ്റ്റ്-റെസ്പോൺസ് അടിസ്ഥാനമാക്കിയുള്ളതുമാണെങ്കിൽ. "ഒരു അഭ്യർത്ഥന വായിക്കുക, അത് പ്രോസസ്സ് ചെയ്യുക, ഒരു പ്രതികരണം എഴുതുക" എന്നതാണ് ലോജിക് എങ്കിൽ, സ്ട്രീമുകൾ അനുയോജ്യമാണ്.
- നിങ്ങൾ അറിയപ്പെടുന്ന, ലൈൻ-ബേസ്ഡ് അല്ലെങ്കിൽ ഫിക്സഡ്-ലെങ്ത് സന്ദേശ പ്രോട്ടോക്കോളിനായി ഒരു ക്ലയിന്റ് നിർമ്മിക്കുകയാണെങ്കിൽ. ഉദാഹരണത്തിന്, ഒരു Redis സെർവറുമായോ ഒരു ലളിതമായ FTP സെർവറുമായോ സംവദിക്കുന്നത്.
- കോഡിന്റെ വായനാക്ഷമതയ്ക്കും രേഖീയവും ഇംപറേറ്റീവുമായ ശൈലിക്കും നിങ്ങൾ മുൻഗണന നൽകുന്നുവെങ്കിൽ. സ്ട്രീമുകളോടൊപ്പമുള്ള
async/await
സിന്റാക്സ് അസിൻക്രണസ് പ്രോഗ്രാമിംഗിൽ പുതിയ ഡെവലപ്പർമാർക്ക് മനസ്സിലാക്കാൻ എളുപ്പമാണ്. - വേഗതയേറിയ പ്രോട്ടോടൈപ്പിംഗ് പ്രധാനമാണെങ്കിൽ. കുറച്ച് വരി കോഡിൽ നിങ്ങൾക്ക് ഒരു ലളിതമായ ക്ലയിന്റോ സെർവറോ സ്ട്രീമുകൾ ഉപയോഗിച്ച് സജ്ജീകരിക്കാൻ കഴിയും.
ട്രാൻസ്പോർട്ടുകളും പ്രോട്ടോക്കോളുകളും തിരഞ്ഞെടുക്കേണ്ട സാഹചര്യങ്ങൾ...
- നിങ്ങൾ ആദ്യം മുതൽ ഒരു സങ്കീർണ്ണമായ അല്ലെങ്കിൽ കസ്റ്റം നെറ്റ്വർക്ക് പ്രോട്ടോക്കോൾ നടപ്പിലാക്കുകയാണെങ്കിൽ. ഇതാണ് പ്രാഥമിക ഉപയോഗം. ഗെയിമിംഗ്, ഫിനാൻഷ്യൽ ഡാറ്റ ഫീഡുകൾ, IoT ഉപകരണങ്ങൾ, അല്ലെങ്കിൽ പിയർ-ടു-പിയർ ആപ്ലിക്കേഷനുകൾ എന്നിവയ്ക്കുള്ള പ്രോട്ടോക്കോളുകളെക്കുറിച്ച് ചിന്തിക്കുക.
- നിങ്ങളുടെ പ്രോട്ടോക്കോൾ ഉയർന്ന ഇവന്റ്-ഡ്രിവൺ ആണ്, പൂർണ്ണമായും റിക്വസ്റ്റ്-റെസ്പോൺസ് അല്ലാത്തതാണെങ്കിൽ. സെർവറിന് എപ്പോൾ വേണമെങ്കിലും ക്ലയിന്റിന് ആവശ്യപ്പെടാത്ത സന്ദേശങ്ങൾ അയയ്ക്കാൻ കഴിയുമെങ്കിൽ, പ്രോട്ടോക്കോളുകളുടെ കോൾബാക്ക്-ബേസ്ഡ് സ്വഭാവം കൂടുതൽ സ്വാഭാവികമാണ്.
- നിങ്ങൾക്ക് പരമാവധി പ്രകടനക്ഷമതയും കുറഞ്ഞ ഓവർഹെഡും ആവശ്യമാണെങ്കിൽ. പ്രോട്ടോക്കോളുകൾ നിങ്ങൾക്ക് ഇവന്റ് ലൂപ്പിലേക്ക് കൂടുതൽ നേരിട്ടുള്ള പാത നൽകുന്നു, സ്ട്രീംസ് API-യുമായി ബന്ധപ്പെട്ട ചില ഓവർഹെഡുകൾ ഒഴിവാക്കുന്നു.
- നിങ്ങൾക്ക് കണക്ഷനിൽ സൂക്ഷ്മമായ നിയന്ത്രണം ആവശ്യമാണെങ്കിൽ. ഇതിൽ മാനുവൽ ബഫർ മാനേജ്മെന്റ്, വ്യക്തമായ ഫ്ലോ കൺട്രോൾ (
pause/resume_writing
), കണക്ഷൻ ലൈഫ് സൈക്കിളിന്റെ വിശദമായ കൈകാര്യം ചെയ്യൽ എന്നിവ ഉൾപ്പെടുന്നു. - നിങ്ങൾ ഒരു നെറ്റ്വർക്ക് ഫ്രെയിംവർക്കോ ലൈബ്രറിയോ നിർമ്മിക്കുകയാണെങ്കിൽ. നിങ്ങൾ മറ്റ് ഡെവലപ്പർമാർക്ക് ഒരു ഉപകരണം നൽകുകയാണെങ്കിൽ, പ്രോട്ടോക്കോൾ/ട്രാൻസ്പോർട്ട് API-യുടെ കരുത്തുറ്റതും വഴക്കമുള്ളതുമായ സ്വഭാവം പലപ്പോഴും ശരിയായ അടിത്തറയാണ്.
ഉപസംഹാരം: അസിൻക്യോയുടെ അടിത്തറയെ സ്വീകരിക്കാം
പൈത്തണിന്റെ asyncio
ലൈബ്രറി ലേയേർഡ് ഡിസൈനിന്റെ ഒരു മാസ്റ്റർപീസ് ആണ്. ഹൈ-ലെവൽ സ്ട്രീംസ് API ആക്സസ് ചെയ്യാവുന്നതും ഉൽപ്പാദനക്ഷമവുമായ ഒരു എൻട്രി പോയിന്റ് നൽകുമ്പോൾ, ലോ-ലെവൽ ട്രാൻസ്പോർട്ട്, പ്രോട്ടോക്കോൾ API ആണ് അസിൻക്യോയുടെ നെറ്റ്വർക്കിംഗ് കഴിവുകളുടെ യഥാർത്ഥവും ശക്തവുമായ അടിത്തറ. I/O മെക്കാനിസത്തെ (ട്രാൻസ്പോർട്ട്) ആപ്ലിക്കേഷൻ ലോജിക്കിൽ (പ്രോട്ടോക്കോൾ) നിന്ന് വേർതിരിക്കുന്നതിലൂടെ, അത് സങ്കീർണ്ണമായ നെറ്റ്വർക്ക് ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിന് കരുത്തുറ്റതും അളക്കാവുന്നതും അവിശ്വസനീയമാംവിധം വഴക്കമുള്ളതുമായ ഒരു മാതൃക നൽകുന്നു.
ഈ ലോ-ലെവൽ അബ്സ്ട്രാക്ഷൻ മനസ്സിലാക്കുന്നത് ഒരു അക്കാദമിക് വ്യായാമം മാത്രമല്ല; ലളിതമായ ക്ലയിന്റുകൾക്കും സെർവറുകൾക്കും അപ്പുറത്തേക്ക് പോകാൻ നിങ്ങളെ പ്രാപ്തരാക്കുന്ന ഒരു പ്രായോഗിക വൈദഗ്ധ്യമാണിത്. ഏത് നെറ്റ്വർക്ക് പ്രോട്ടോക്കോളിനെയും നേരിടാനുള്ള ആത്മവിശ്വാസം, സമ്മർദ്ദത്തിൽ പ്രകടനക്ഷമതയ്ക്കായി ഒപ്റ്റിമൈസ് ചെയ്യാനുള്ള നിയന്ത്രണം, പൈത്തണിൽ അടുത്ത തലമുറയിലെ ഉയർന്ന പ്രകടനക്ഷമതയുള്ള, അസിൻക്രണസ് സേവനങ്ങൾ നിർമ്മിക്കാനുള്ള കഴിവ് എന്നിവ ഇത് നിങ്ങൾക്ക് നൽകുന്നു. അടുത്ത തവണ നിങ്ങൾ ഒരു വെല്ലുവിളി നിറഞ്ഞ നെറ്റ്വർക്കിംഗ് പ്രശ്നം നേരിടുമ്പോൾ, ഉപരിതലത്തിന് തൊട്ടുതാഴെ കിടക്കുന്ന ശക്തിയെ ഓർക്കുക, ട്രാൻസ്പോർട്ടുകളുടെയും പ്രോട്ടോക്കോളുകളുടെയും മനോഹരമായ ജോഡിയെ ആശ്രയിക്കാൻ മടിക്കരുത്.